/**************************************************************************************************
* Title: SumColor.inl
* Author: Gael Huber
* Description: Defines color functions
**************************************************************************************************/

/**************************************************************************************************
* Default constructor
**************************************************************************************************/
inline Color::Color(void)
	: r(0.0f), g(0.0f), b(0.0f), a(0.0f)
{ }

/**************************************************************************************************
* Constructor given as bitmask
**************************************************************************************************/
inline Color::Color(unsigned int argb) {
	const float f = 1.0f / 255.0f;
	r = f * (float)(unsigned char)(argb >> 16);
	g = f * (float)(unsigned char)(argb >> 8);
	b = f * (float)(unsigned char)(argb >> 0);
	a = f * (float)(unsigned char)(argb >> 24);
}

/**************************************************************************************************
* Constructor from an array
**************************************************************************************************/
inline Color::Color(const float* f)
	: r(f[0]), g(f[1]), b(f[2]), a(f[3])
{ }

/**************************************************************************************************
* Constructor given values
**************************************************************************************************/
inline Color::Color(float r, float g, float b, float a)
	: r(r), g(g), b(b), a(a)
{ }

/**************************************************************************************************
* Copy constructor
**************************************************************************************************/
inline Color::Color(const Color& rhs)
	: r(rhs.r), g(rhs.g), b(rhs.b), a(rhs.a)
{ }

/**************************************************************************************************
* Destructor
**************************************************************************************************/
inline Color::~Color(void)
{ }

/**************************************************************************************************
* Return the argb values as an unsigned long
**************************************************************************************************/
inline Color::operator unsigned int(void) const {
	// We want to ensure color bounds are enforced as this does not take place during standard
	// mathematical procedures
	return	(r >= 1.0f ? 0xff : r <= 0.0f ? 0x00 : (unsigned int)(r * 255.0f + 0.5f) << 16) |
			(g >= 1.0f ? 0xff : g <= 0.0f ? 0x00 : (unsigned int)(g * 255.0f + 0.5f) << 8) |
			(b >= 1.0f ? 0xff : b <= 0.0f ? 0x00 : (unsigned int)(b * 255.0f + 0.5f) << 0) |
			(a >= 1.0f ? 0xff : a <= 0.0f ? 0x00 : (unsigned int)(a * 255.0f + 0.5f) << 24);
}

/**************************************************************************************************
* Return data as a float array
**************************************************************************************************/
inline Color::operator float*(void) {
	return (float*) this;
}

/**************************************************************************************************
* Return data as a constant float array
**************************************************************************************************/
inline Color::operator const float*(void) const {
	return (const float*) this;
}

/**************************************************************************************************
* Assignment operator
**************************************************************************************************/
inline Color& Color::operator=(const Color& rhs) {
	if(&rhs == this)
		return *this;

	r = rhs.r;
	g = rhs.g;
	b = rhs.b;
	a = rhs.a;
	return *this;
}

/**************************************************************************************************
* Returns the sum of two colors
**************************************************************************************************/
inline Color& Color::operator+=(const Color& rhs) {
	r += rhs.r;
	g += rhs.g;
	b += rhs.b;
	a += rhs.a;
	return *this;
}

/**************************************************************************************************
* Returns the difference between two colors
**************************************************************************************************/
inline Color& Color::operator-=(const Color& rhs) {
	r -= rhs.r;
	g -= rhs.g;
	b -= rhs.b;
	a -= rhs.a;
	return *this;
}

/**************************************************************************************************
* Returns the product of a color and a scalar
**************************************************************************************************/
inline Color& Color::operator*=(float rhs) {
	r *= rhs;
	g *= rhs;
	b *= rhs;
	a *= rhs;
	return *this;
}

/**************************************************************************************************
* Returns the dividend of a color and a scalar
**************************************************************************************************/
inline Color& Color::operator/=(float rhs) {
	const float f = 1.0f / rhs;
	r *= f;
	g *= f;
	b *= f;
	a *= f;
	return *this;
}

/**************************************************************************************************
* Returns a positive version of the data
**************************************************************************************************/
inline Color Color::operator+(void) const {
	return *this;
}

/**************************************************************************************************
* Returns a negated version of the data
**************************************************************************************************/
inline Color Color::operator-(void) const {
	return Color(-r, -g, -b, -a);
}

/**************************************************************************************************
* Returns the sum of two colors
**************************************************************************************************/
inline Color Color::operator+(const Color& rhs) const {
	return Color(r + rhs.r, g + rhs.g, b + rhs.b, a + rhs.a);
}

/**************************************************************************************************
* Returns the difference between two colors
**************************************************************************************************/
inline Color Color::operator-(const Color& rhs) const {
	return Color(r - rhs.r, g - rhs.g, b - rhs.b, a - rhs.a);
}

/**************************************************************************************************
* Returns a color multiplied by a scalar
**************************************************************************************************/
inline Color Color::operator*(float rhs) const {
	return Color(r * rhs, g * rhs, b * rhs, a * rhs);
}

/**************************************************************************************************
* Returns a color divided by a scalar
**************************************************************************************************/
inline Color Color::operator/(float rhs) const {
	const float f = 1.0f / rhs;
	return Color(r * f, g * f, b * f, a * f);
}

/**************************************************************************************************
* Returns a color multiplied by a scalar
**************************************************************************************************/
inline Color operator*(float lhs, const Color& rhs) {
	return Color(lhs * rhs.r, lhs * rhs.g, lhs * rhs.b, lhs * rhs.a);
}

/**************************************************************************************************
* Equivalence operator
**************************************************************************************************/
inline bool Color::operator==(const Color& rhs) const {
	return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a;
}

/**************************************************************************************************
* Non-equivalence
**************************************************************************************************/
inline bool Color::operator!=(const Color& rhs) const {
	return r != rhs.r || g != rhs.g || b != rhs.b || a != rhs.a;
}

/**************************************************************************************************
* Return the negative of the color, (1-r, 1-g, 1-b, a)
**************************************************************************************************/
inline Color* ColorNegative(Color* pOut, const Color* pC) {
	pOut->r = 1.0f - pC->r;
	pOut->g = 1.0f - pC->g;
	pOut->b = 1.0f - pC->b;
	pOut->a = pC->a;
	return pOut;
}

/**************************************************************************************************
* Add two colors
**************************************************************************************************/
inline Color* ColorAdd(Color* pOut, const Color* pC1, const Color* pC2) {
	pOut->r = pC1->r + pC2->r;
	pOut->g = pC1->g + pC2->g;
	pOut->b = pC1->b + pC2->b;
	pOut->a = pC1->a + pC2->a;
	return pOut;
}

/**************************************************************************************************
* Subtract two colors
**************************************************************************************************/
inline Color* ColorSub(Color* pOut, const Color* pC1, const Color* pC2) {
	pOut->r = pC1->r - pC2->r;
	pOut->g = pC1->g - pC2->g;
	pOut->b = pC1->b - pC2->b;
	pOut->a = pC1->a - pC2->a;
	return pOut;
}

/**************************************************************************************************
* Scale a color by a given factor
**************************************************************************************************/
inline Color* ColorScale(Color* pOut, const Color* pC, float s) {
	pOut->r = pC->r * s;
	pOut->g = pC->g * s;
	pOut->b = pC->b * s;
	pOut->a = pC->a * s;
	return pOut;
}

/**************************************************************************************************
* Modulate colors (r1*r2, g1*g2, b1*b2, a1*a2)
**************************************************************************************************/
inline Color* ColorModulate(Color* pOut, const Color* pC1, const Color* pC2) {
	pOut->r = pC1->r * pC2->r;
	pOut->g = pC1->g * pC2->g;
	pOut->b = pC1->b * pC2->b;
	pOut->a = pC1->a * pC2->a;
	return pOut;
}

/**************************************************************************************************
* Lerp of r, g, b, and a. C1 + s(C2 - C1)
**************************************************************************************************/
inline Color* ColorLerp(Color* pOut, const Color* pC1, const Color* pC2, float s) {
	Color diff;
	ColorSub(&diff, pC2, pC1);
	ColorScale(&diff, &diff, s);
	ColorAdd(pOut, pC1, &diff);
	return pOut;
}